# -*- encoding -*-

import json
import time
import requests
from eth_utils import keccak, to_hex
from lib.public import requestRetry


class BSC(object):

    def __init__(self, rpc_http):
        self.url = rpc_http

    def topi_signature(self, transfer_event_abi):
        """TODO
            :transfer_event_abi:
                过滤事件示例:
                JS 中： Transfer(address indexed from, address indexed to, uint256 value)
                python: Transfer(address,address,uint256)
            格式不对, 结果不同
        :return:
        """
        # 返回主题进行签名
        event_signature = keccak(text=transfer_event_abi)
        topic = to_hex(event_signature)
        return topic

    def health_check(self):
        # RPC健康检查
        try:
            self.get_block_number()
        except Exception as e:
            print(f'[健康检查] RPC连接失败: {e}')
            return False
        return True

    @requestRetry(max_retries=3)
    def get_block_number(self):
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_blockNumber",
            "params": [],
            "id": 56
        }
        # 获取区块链上最新区块的编号
        headers = {"Content-Type": "application/json"}
        # 发送 POST 请求
        response = requests.post(self.url, json=payload, headers=headers)
        if response.status_code == 200:
            # 返回结果
            resp = response.json()
            return resp.get('result')

    @requestRetry()
    def get_timestamp(self, block_number):
        """TODO
            - 获取 - 代币转账跟踪和钱包更新
        :param block_number:
        :param flag:
        :return:
        """
        # 通过区块标识符检索区块的详细信息
        if not block_number.startswith('0x'):
            block_number = str(hex(block_number))
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_getBlockByNumber",
            "params": [block_number, False],
            "id": 56
        }
        response = requests.post(self.url, json=payload)
        if response.status_code == 200:
            resp = response.json()
            timestamp = resp.get('result', {}).get('timestamp', '0x0')
            return timestamp
        raise ValueError(f'错误 [get_timestamp] 失败, error info: {response.text}')

    @requestRetry()
    def get_transaction_hash(self, transactionHash):
        """TODO
            - 获取 - to address
        """
        # 通过区块标识符检索区块的详细信息
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_getTransactionByHash",
            "params": [transactionHash],
            "id": 56
        }
        response = requests.post(self.url, json=payload)
        if response.status_code == 200:
            resp = response.json()
            return resp.get('result', {})
        raise ValueError(f'错误 [get_transaction_hash] 获取to address [失败], '
                         f'error info: {response.text}')

    @requestRetry()
    def get_transaction_receipts(self, transactionHash):
        """TODO
            - 获取 - 代币转账跟踪和钱包更新
        """
        # 通过区块标识符检索区块的详细信息
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_getTransactionReceipt",
            "params": [transactionHash],
            "id": 56
        }
        response = requests.post(self.url, json=payload)
        if response.status_code == 200:
            resp = response.json()
            return resp.get('result', [])
        raise ValueError(f'错误 [get_transaction_receipts] 获取代币转账 [失败], error info: {response.text}')

    @requestRetry()
    def get_code(self, address):
        """TODO
            - 获取 - 代币转账跟踪和钱包更新
        """
        # 通过区块标识符检索区块的详细信息
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_getCode",
            "params": [address, 'latest'],
            "id": 56
        }
        response = requests.post(self.url, json=payload)
        if response.status_code == 200:
            resp = response.json()
            if not resp.get('result'):
                raise ValueError(
                    f'错误 [get_code] 获取代币智能合约的编译字节码 [失败], error info:'
                    f' {response.text}')
            result = resp.get('result')
            if "0x" == result:
                return True
            return False
        raise ValueError(f'错误 [get_code] 获取代币智能合约的编译字节码 [失败], error info:'
                         f' {response.text}')


    @requestRetry()
    def get_logs(self, address, from_block, to_block, transfer_text=None):
        """TODO
            - 获取给定过滤器对象匹配的所有日志数组
        :param address:
        :param from_block:
        :param to_block:
        :return: dict
        """
        if transfer_text:
            topic = [self.topi_signature(transfer_text)]
        else:
            topic = []

        # 获取给定过滤器对象匹配的所有日志数组
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_getLogs",
            "params": [{
                "fromBlock": from_block,
                "toBlock": to_block,
                "address": address,
                "topics": topic
            }],
            "id": 56
        }
        response = requests.post(self.url, json=payload)
        _resp = response.json()
        if 'result' in _resp:
            # return _resp
            return True, _resp.get('result')
        else:
            # 这里需要客户自己以后做兼容
            error =  _resp.get('error', {})
            if error.get('code') == -32000:
                # 块区间没有数据
                print(f'[get_logs] 块区间没有数据, fromBlock{from_block}, toBlock: '
                      f'{to_block}, address: {address}')
                return True, []
            if error.get('code') == -32012:
                # 块范围 - 阈值超出
                try:
                    maxAllowedRange = error['code']['data']['details']['maxAllowedRange']
                    err = f'此RPC_HTTP: {self.url}, 支持的最大阈值: {maxAllowedRange}'
                    print(err)
                    # 可以在主程序中做阈值处理
                    return False, error
                except Exception:
                    print(f'获取最大查询阈值(maxAllowedRange)失败, error info: '
                          f'{json.dumps(error)}')
                    return False, error
            elif 'rate limit' in error.get("message") or error.get('code') == \
                    429:
                # 速率限制时等待更长时间
                time.sleep(3)
                raise requests.Timeout('速率限制时等待更长时间')
            elif 'connection' in error.get("message") or 'ECONNRESET' in \
                    error.get("message"):
                # 连接问题时等待更长时间
                time.sleep(2)
                raise requests.Timeout('连接问题时等待更长时间')
            elif 'server' in error.get("message") or error.get('code') >= 500:
                # 服务器错误
                time.sleep(1.5)
                raise requests.Timeout('服务器错误')
            elif 'request timed out' in error.get("message"):
                print(
                    f'错误[get_logs], 请确认服务器是否启动 error info: '
                    f'{error.get("message")}')
                raise TimeoutError('request timed out')
            else:
                # 请求参数问题, 无需重试
                print(f'未知错误[get_logs], error info: {error.get("message")}')
                return False, error



if __name__ == '__main__':
    bsc = BSC('https://bsc.blockrazor.xyz')

    get_block_number_data = {
        "jsonrpc": "2.0",
        "method": "eth_blockNumber",
        # "params": [{'nativeCurrency': {'name': "BNB", 'symbol':
        #     "BNB", 'decimals': 18}}],
        "params": [],
        "id": 56
    }
    # print(bsc.get_block_number(get_block_number_data))
    # 主题会对 - 结果产生影响
    # print(bsc.get_logs('0x8ff795a6f4d97e7887c79bea79aba5cc76444adf', '0x3d0a8e0',
    #                    '0x3d0adbc', '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'))
    transfer_text = "Transfer(address,address,uint256)"
    print(bsc.get_logs(['0xe9e7cea3dedca5984780bafc599bd69add087d56'],
                       '0x5b8ee9',
                       '0x5b8eea',
                       transfer_text,
                       ))
    # print(bsc.get_code('0x2bC3e28253544772281f35450604D309Ae204ca2'))
    # a = "0x38ed173900000000000000000000000000000000000000000000000041412df137eaa000000000000000000000000000000000000000000000000093a57ce6ebbfa8000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000ef575087f1e7bec54046f98119c8c392a37c51dd0000000000000000000000000000000000000000000000000000000060676ee800000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ff795a6f4d97e7887c79bea79aba5cc76444adf000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d56"
    # print(a[34:74])
    # print(a[226:266])
    # print(bsc.topi_signature(transfer_text))
    # print(bsc.topi_signature(transfer_text))